package com.genntii.examManager.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.genntii.examManager.common.constant.CommonConstant;
import com.genntii.examManager.common.exception.FinalExamExistsException;
import com.genntii.examManager.common.exception.NoAuthenticationOperateException;
import com.genntii.examManager.common.exception.PracticeNotFoundException;
import com.genntii.examManager.common.result.PageResult;
import com.genntii.examManager.domain.dto.ExamAddDTO;
import com.genntii.examManager.domain.entity.Exam;
import com.genntii.examManager.domain.entity.Practice;
import com.genntii.examManager.domain.entity.Teacher;
import com.genntii.examManager.domain.question.mongo.ExamDetail;
import com.genntii.examManager.domain.question.mongo.QuestionBankMongo;
import com.genntii.examManager.domain.question.vo.*;
import com.genntii.examManager.domain.vo.PracticeVO;
import com.genntii.examManager.mapper.*;
import com.genntii.examManager.service.PracticeRecordService;
import com.genntii.examManager.service.PracticeService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;

@Service
public class PracticeServiceImpl extends ServiceImpl<PracticeMapper, Practice> implements PracticeService {

    @Resource
    private PracticeMapper practiceMapper;

    @Resource
    private CourseMapper courseMapper;

    @Resource
    private TeacherMapper teacherMapper;

    @Resource
    private MongoTemplate mongoTemplate;

    @Resource
    private PracticeRecordMapper practiceRecordMapper;

    @Resource
    private CourseRecordMapper courseRecordMapper;

    @Resource
    private HttpServletRequest request;

    @Resource
    private SubjectMapper subjectMapper;

    @Override
    public PageResult<PracticeVO> getPracticeList(Integer pageNum, Integer pageSize, Long userId, Long courseId) {
        ArrayList<Practice> practices = practiceMapper.getPracticeList((pageNum-1)*pageSize,pageSize,courseId);
        ArrayList<PracticeVO> practiceVOS = new ArrayList<>();
        for (Practice practice : practices){
            PracticeVO build = PracticeVO.builder()
                    .id(practice.getId())
                    .practiceName(practice.getPracticeName())
                    .courseName(courseMapper.getCourseById(practice.getCourseId()).getCourseName())
                    .teacherName(teacherMapper.selectById(practice.getTeacherId()).getName())
                    .questionCount(practice.getQuestionCount())
                    .startTime(practice.getStartTime())
                    .endTime(practice.getEndTime())
                    .status(practice.getStatus())
                    .build();
            if(request.getAttribute(CommonConstant.USER_ID) != null) build.setIsCompleted(practiceRecordMapper.selectByUserPractice(userId, practice.getId()).getStatus());
            practiceVOS.add(build);
        }
        return PageResult.build(practiceVOS, practiceMapper.getPracticeTotal());
    }

    @Override
    public ExamDetailVO getPractice(Long practiceId) {
        if (practiceMapper.selectById(practiceId) == null){
            throw new PracticeNotFoundException("未找到该练习");
        }

        return new ExamDetailVO(Objects.requireNonNull(mongoTemplate.findOne(new Query(new Criteria("_id").is(practiceId)),
                ExamDetail.class,
                "practiceDetail")));
    }

    @Override
    @Transactional
    public void addExam(ExamAddDTO examAddDTO, ArrayList<Long> mongoId, Long userId) {
        Long teacherId = teacherMapper.selectOne(new QueryWrapper<Teacher>().eq("user_id", userId)).getId();
        if (!Objects.equals(courseMapper.selectById(examAddDTO.getCourseId()).getTeacherId(), teacherId)){
            throw new NoAuthenticationOperateException("无权限访问");
        }
        Topic topic = new Topic();
        List<QuestionBankMongo> question = new ArrayList<>();
        int maxScore = 0;
        int questionCount = 0;
        ArrayList<Long> userIds = courseRecordMapper.getUserIdsByCourse(examAddDTO.getCourseId());
        if (mongoId!=null&&!mongoId.isEmpty()){

            question = mongoTemplate.find(new Query(new Criteria("_id").in(mongoId)), QuestionBankMongo.class);
            Map<Long, Integer> scoreMap = new HashMap<>();



            for (QuestionBankMongo questionBankMongo:question){
                scoreMap.put(questionBankMongo.get_id(),questionBankMongo.getScore());
                maxScore += questionBankMongo.getScore();
                questionCount ++;
                switch (questionBankMongo.getType()){
                    case 1:
                        ArrayList<SingleChoice> singleChoices = topic.getSingleChoices();
                        singleChoices.add(questionBankMongo.getTopic().getSingleChoice());
                        topic.setSingleChoices(singleChoices);
                    case 2:
                        ArrayList<MultipleChoice> multipleChoices = topic.getMultipleChoices();
                        multipleChoices.add(questionBankMongo.getTopic().getMultipleChoice());
                        topic.setMultipleChoices(multipleChoices);
                    case 3:
                        ArrayList<TrueFalse> trueFalses = topic.getTrueFalses();
                        trueFalses.add(questionBankMongo.getTopic().getTrueFalse());
                        topic.setTrueFalses(trueFalses);
                    case 4:
                        ArrayList<Vocabulary> vocabularies = topic.getVocabularies();
                        vocabularies.add(questionBankMongo.getTopic().getVocabulary());
                        topic.setVocabularies(vocabularies);
                }
            }
        }

        if (topic.getMultipleChoices()!=null&&!topic.getMultipleChoices().isEmpty()){
            for (MultipleChoice multipleChoice:examAddDTO.getTopicDTO().getMultipleChoices()){
                ArrayList<MultipleChoice> multipleChoices = topic.getMultipleChoices();
                multipleChoices.add(multipleChoice);
                topic.setMultipleChoices(multipleChoices);
            }
        }

        if (topic.getSingleChoices()!=null && !topic.getSingleChoices().isEmpty()){
            for (SingleChoice singleChoice:examAddDTO.getTopicDTO().getSingleChoices()){
                ArrayList<SingleChoice> singleChoices = topic.getSingleChoices();
                singleChoices.add(singleChoice);
                topic.setSingleChoices(singleChoices);
            }
        }

        if (topic.getTrueFalses()!=null&&!topic.getTrueFalses().isEmpty()){
            for (TrueFalse trueFalse: topic.getTrueFalses()){
                ArrayList<TrueFalse> trueFalses = topic.getTrueFalses();
                trueFalses.add(trueFalse);
                topic.setTrueFalses(trueFalses);
            }
        }

        if (topic.getVocabularies()!=null && !topic.getVocabularies().isEmpty()){
            for (Vocabulary vocabulary:examAddDTO.getTopicDTO().getVocabularies()){
                ArrayList<Vocabulary> vocabularies = topic.getVocabularies();
                vocabularies.add(vocabulary);
                topic.setVocabularies(vocabularies);
            }
        }

        Practice practice = Practice.builder()
                .practiceName(examAddDTO.getName())
                .courseId(examAddDTO.getCourseId())
                .teacherId(teacherId)
                .startTime(examAddDTO.getStartTime())
                .endTime(examAddDTO.getEndTime())
                .createTime(LocalDateTime.now())
                .updateTime(LocalDateTime.now())
                .questionCount(questionCount)
                .build();


        practiceMapper.insert(practice);
        ExamDetail examDetail = ExamDetail.builder()
                ._id(practice.getId())
                .teacherName(teacherMapper.selectById(teacherId).getName())
                .startTime(practice.getStartTime())
                .endTime(practice.getEndTime())
                .score(maxScore)
                .topic(topic)
                .build();
        if (!question.isEmpty()){
            examDetail.setSubjectName(subjectMapper.selectById(question.get(1).getSubject()).getSubjectName());
        }
        mongoTemplate.insert(examDetail,"practiceDetail");
        practiceRecordMapper.insertBatch(practice.getId(),userIds);
    }

    @Override
    public void setStatus(Byte status, Long practiceId) {
        practiceMapper.setStatus(status,practiceId);
    }
}
